{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3393d0e8",
   "metadata": {},
   "source": [
    "本节介绍线性代数中的基本运算以及代码的实现"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33f6fcf3",
   "metadata": {},
   "source": [
    "### 2.3.1 标量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d705d3f",
   "metadata": {},
   "source": [
    "标量由一个元素的张量表示，例子如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3c69ad3a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor(5.), tensor(6.), tensor(1.5000), tensor(9.))"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "x = torch.tensor(3.0)\n",
    "y = torch.tensor(2.0)\n",
    "x+y, x*y, x/y, x**y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18de6a2d",
   "metadata": {},
   "source": [
    "### 2.3.2 向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "345f7a42",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0, 1, 2, 3])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.arange(4)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c47d1f4f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(3)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "449230fc",
   "metadata": {},
   "source": [
    "### 长度、维度和形状"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a970b573",
   "metadata": {},
   "source": [
    "通过调用len函数访问张量的长度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "33a07a29",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ef7a57b5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([2, 2])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.reshape((2,2)).shape #张量的维度用来表示张量具有的轴数，张量的某个轴的维数就是这个轴的长度"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd4b5e27",
   "metadata": {},
   "source": [
    "### 2.3.3 矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6e3e26eb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0,  1,  2,  3],\n",
       "        [ 4,  5,  6,  7],\n",
       "        [ 8,  9, 10, 11],\n",
       "        [12, 13, 14, 15],\n",
       "        [16, 17, 18, 19]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "A = torch.arange(20).reshape(5,4)\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "6fdc4d2a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0,  4,  8, 12, 16],\n",
       "        [ 1,  5,  9, 13, 17],\n",
       "        [ 2,  6, 10, 14, 18],\n",
       "        [ 3,  7, 11, 15, 19]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "301e4c5b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[1, 2, 3],\n",
       "        [2, 0, 4],\n",
       "        [3, 4, 5]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "B = torch.tensor([[1,2,3],[2,0,4],[3,4,5]])\n",
    "B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4ea7965a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[True, True, True],\n",
       "        [True, True, True],\n",
       "        [True, True, True]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "B == B.T"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05570561",
   "metadata": {},
   "source": [
    "### 2.3.4 张量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b13b9d05",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[[ 0,  1,  2,  3],\n",
       "         [ 4,  5,  6,  7],\n",
       "         [ 8,  9, 10, 11]],\n",
       "\n",
       "        [[12, 13, 14, 15],\n",
       "         [16, 17, 18, 19],\n",
       "         [20, 21, 22, 23]]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X= torch.arange(24).reshape(2,3,4)\n",
    "X"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0718dc12",
   "metadata": {},
   "source": [
    "### 2.3.5 张量算法的基本性质"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6bb620fd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[ 0.,  1.,  2.,  3.],\n",
       "         [ 4.,  5.,  6.,  7.],\n",
       "         [ 8.,  9., 10., 11.],\n",
       "         [12., 13., 14., 15.],\n",
       "         [16., 17., 18., 19.]]),\n",
       " tensor([[ 0.,  2.,  4.,  6.],\n",
       "         [ 8., 10., 12., 14.],\n",
       "         [16., 18., 20., 22.],\n",
       "         [24., 26., 28., 30.],\n",
       "         [32., 34., 36., 38.]]))"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = torch.arange(20,dtype = torch.float32).reshape(5,4)\n",
    "B = A.clone()\n",
    "A, A+B"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a72c7e90",
   "metadata": {},
   "source": [
    "两个矩阵按元素乘法称为Hadamard积。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "fccb4de5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[  0.,   1.,   4.,   9.],\n",
       "        [ 16.,  25.,  36.,  49.],\n",
       "        [ 64.,  81., 100., 121.],\n",
       "        [144., 169., 196., 225.],\n",
       "        [256., 289., 324., 361.]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A * B"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "564252ba",
   "metadata": {},
   "source": [
    "将张量乘以或加上一个标量不回改变张量的形状，其中张量的每个元素都将与标量相加或相乘"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d15a176c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[[ 2,  3,  4,  5],\n",
       "          [ 6,  7,  8,  9],\n",
       "          [10, 11, 12, 13]],\n",
       " \n",
       "         [[14, 15, 16, 17],\n",
       "          [18, 19, 20, 21],\n",
       "          [22, 23, 24, 25]]]),\n",
       " torch.Size([2, 3, 4]))"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = 2\n",
    "X = torch.arange(24).reshape(2,3,4)\n",
    "a + X, (a * X).shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63c15009",
   "metadata": {},
   "source": [
    "### 2.3.6 降维"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "444e2b88",
   "metadata": {},
   "source": [
    "可以对任意形状的张量求和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "15539d52",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([0., 1., 2., 3.]), tensor(6.))"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = torch.arange(4, dtype=torch.float32)\n",
    "x, x.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3b257529",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([5, 4]), tensor(190.))"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.shape, A.sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b94c9f83",
   "metadata": {},
   "source": [
    "默认情况下，求和函数会沿所有轴降低张量的维度，使它变成一个标量。同时我们还能指定张量沿哪一个轴来通过求和降低维度。\n",
    "通过指定axis=0，因此输入轴的维数再输出形状中消失。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "93e3953b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([40., 45., 50., 55.]), torch.Size([4]))"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A_sum_axis0 = A.sum(axis=0)\n",
    "A_sum_axis0, A_sum_axis0.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32d1f35d",
   "metadata": {},
   "source": [
    "指定axis=1将所有列的元素将为，因此输入轴1的维数再输出形状中消失。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "178f6082",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([ 6., 22., 38., 54., 70.]), torch.Size([5]))"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A_sum_axis1 = A.sum(axis=1)\n",
    "A_sum_axis1, A_sum_axis1.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd1f2357",
   "metadata": {},
   "source": [
    "沿着行和列对矩阵求和，等价于对矩阵所有元素进行求和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "e9f8c417",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(190.)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.sum(axis=[0,1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "373e41db",
   "metadata": {},
   "source": [
    "求平均值，即将总和除以元素总数来计算机平均值。我们可以调用函数来计算任意形状张量的平均值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e0da1894",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor(9.5000), tensor(9.5000))"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.mean(), A.sum()/A.numel()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "633ea3a4",
   "metadata": {},
   "source": [
    "同样计算平均值的函数也可以沿指定轴降低张量的维度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "f84d855b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([ 8.,  9., 10., 11.]), tensor([ 8.,  9., 10., 11.]))"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.mean(axis=0), A.sum(axis=0)/A.shape[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c650f61",
   "metadata": {},
   "source": [
    "非降维求和"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9f8fc18",
   "metadata": {},
   "source": [
    "即求和或求均值时保持轴数不变"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "54fc8364",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 6.],\n",
       "        [22.],\n",
       "        [38.],\n",
       "        [54.],\n",
       "        [70.]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum_A = A.sum(axis=1, keepdims=True)\n",
    "sum_A"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1437820c",
   "metadata": {},
   "source": [
    "sum_A对每行进行求和后仍保持两个轴，我们可以通过广播将A除以sum_A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "0b2dcb0e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0.0000, 0.1667, 0.3333, 0.5000],\n",
       "        [0.1818, 0.2273, 0.2727, 0.3182],\n",
       "        [0.2105, 0.2368, 0.2632, 0.2895],\n",
       "        [0.2222, 0.2407, 0.2593, 0.2778],\n",
       "        [0.2286, 0.2429, 0.2571, 0.2714]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A / sum_A"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc6d6faa",
   "metadata": {},
   "source": [
    "如果我们想沿某个轴做累计总和，可以调用cumsum函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "ce96a9d6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.,  1.,  2.,  3.],\n",
       "        [ 4.,  6.,  8., 10.],\n",
       "        [12., 15., 18., 21.],\n",
       "        [24., 28., 32., 36.],\n",
       "        [40., 45., 50., 55.]])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.cumsum(axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "721de6f1",
   "metadata": {},
   "source": [
    "### 2.3.7 点积（Dot Product）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55e0a747",
   "metadata": {},
   "source": [
    "点积：相同位置乘积的和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "b7c8fb70",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = torch.ones(4,dtype=torch.float32)\n",
    "x,y,torch.dot(x,y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "9012be59",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(6.)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.sum(x * y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c8ae3ef",
   "metadata": {},
   "source": [
    "### 2.3.8 矩阵-向量积"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "433570bc",
   "metadata": {},
   "source": [
    "在代码中，使用张良表示矩阵-向量积。我们使用与点积相同的mv函数。当我们为矩阵A和向量x调用mv时，会执行矩阵-向量积。\n",
    "注意A列的维数必须与x的维数相同"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "4f3d8023",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([5, 4]), torch.Size([4]), tensor([ 14.,  38.,  62.,  86., 110.]))"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A.shape, x.shape,torch.mv(A,x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c953b530",
   "metadata": {},
   "source": [
    "### 2.3.9 矩阵-矩阵乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "fae5bbbc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 6.,  6.,  6.],\n",
       "        [22., 22., 22.],\n",
       "        [38., 38., 38.],\n",
       "        [54., 54., 54.],\n",
       "        [70., 70., 70.]])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "B = torch.ones(4,3)\n",
    "torch.mm(A,B)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6e719f8",
   "metadata": {},
   "source": [
    "### 2.3.10 范数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eefd3949",
   "metadata": {},
   "source": [
    "线性代数中最有用的一些运算符时范数（norm），一个向量的范数告诉我们一个向量有多大。\n",
    "范数的计算如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b5d39ff3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(5.)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "u = torch.tensor([3.0, -4.0])\n",
    "torch.norm(u)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dbb2ea20",
   "metadata": {},
   "source": [
    "L1范数，向量元素绝对值之和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "386a586f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(7.)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.abs(u).sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "57cac552",
   "metadata": {},
   "source": [
    "Lp范数，Frobenius norm范数：矩阵范数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c17d15fb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(6.)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "torch.norm(torch.ones(4,9))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a04c4f4e",
   "metadata": {},
   "source": [
    "范数和目标"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ba64661",
   "metadata": {},
   "source": [
    "### 2.3.11 关于线性代数的更多信息"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28fedd30",
   "metadata": {},
   "source": [
    "### 2.3.12 小结"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f0f5ab0",
   "metadata": {},
   "source": [
    "1.标量，向量，矩阵和张量时线性代数中的基本数学对象\n",
    "2.向量泛化自标量，矩阵泛化自向量\n",
    "3.标量，向量，矩阵和张量分别具有零，一，二和任意数量的轴\n",
    "4.一个张量可以通过sum和mean沿指定的轴降低维度\n",
    "5.两个矩阵的按元素乘法称为Hadamard积，与矩阵乘法不同\n",
    "6.深度学习中了我们经常使用范数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3fe8dbee",
   "metadata": {},
   "source": [
    "### 2.3.13 练习"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "296e6ac3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[True, True, True, True, True],\n",
       "        [True, True, True, True, True],\n",
       "        [True, True, True, True, True],\n",
       "        [True, True, True, True, True]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = torch.arange(20).reshape(4,5)\n",
    "B = A.T\n",
    "C = B.T\n",
    "A == C"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "6f43b9d9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X = torch.arange(24).reshape(2,3,4)\n",
    "len(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "858f3035",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
